
package com.borqs.music.ui;

import com.borqs.music.MediaPlaybackService;
import com.borqs.music.R;
import com.borqs.music.util.EnvironmentCompat;
import com.borqs.music.util.MusicUtils;
import com.borqs.music.util.MusicUtils.ServiceToken;
import com.borqs.music.util.MusicUtils.TypeDefs;

import android.app.ListActivity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.provider.MediaStore;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.AdapterContextMenuInfo;

import java.util.ArrayList;
import java.util.List;

public class DirectoryBrowserActivity extends ListActivity
        implements MusicUtils.Defs, ServiceConnection {
    private FolderListAdapter mAdapter;
    private FolderItem mCurrentSelectItem;
    private ServiceToken mToken;

    static String mCurrentPlaying = null;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
        //setTitle(R.string.folder_title);
        setVolumeControlStream(AudioManager.STREAM_MUSIC);
        mToken = MusicUtils.bindToService(this, this);

        IntentFilter f = new IntentFilter();
        f.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
        f.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
        f.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
        f.addDataScheme("file");
        registerReceiver(mScanListener, f);

        setContentView(R.layout.media_picker_activity);
        MusicUtils.initTitleBar(this, getListView(), getString(R.string.folder_title));
        ListView lv = getListView();
        lv.setOnCreateContextMenuListener(this);
        lv.setTextFilterEnabled(true);

        mAdapter = (FolderListAdapter) getLastNonConfigurationInstance();
        if (mAdapter == null) {
            List<FolderItem> items = getFolderItemList();
            mAdapter = new FolderListAdapter(this, items);
            setListAdapter(mAdapter);
        } else {
            setListAdapter(mAdapter);
        }

        restorPrePosition();

        mTrackIntentFilter.addAction(MediaPlaybackService.META_CHANGED);
        mTrackIntentFilter.addAction(MediaPlaybackService.QUEUE_CHANGED);
        MusicUtils.addNowPlayingListener(this);

        deleteObserver = new DeleteObserver();
        getContentResolver().registerContentObserver(
                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                false,
                deleteObserver);
    }

    @Override
    public Object onRetainNonConfigurationInstance() {
        return mAdapter;
    }

    @Override
    public void onDestroy() {
        ListView lv = getListView();
        if (lv != null) {
            mLastListPosCourse = lv.getFirstVisiblePosition();
            View cv = lv.getChildAt(0);
            if (cv != null) {
                mLastListPosFine = cv.getTop();
            }
        }
        getContentResolver().unregisterContentObserver(deleteObserver);
        MusicUtils.unbindFromService(mToken);
        unregisterReceiver(mScanListener);
        super.onDestroy();
    }

    @Override
    public void onResume() {
        super.onResume();
        registerReceiver(mTrackListListener, mTrackIntentFilter);
        mTrackListListener.onReceive(null, null);

        MusicUtils.setSpinnerState(this);
    }

    private IntentFilter mTrackIntentFilter = new IntentFilter();

    private BroadcastReceiver mTrackListListener = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (MusicUtils.sService != null) {
                try {
                    mCurrentPlaying = MusicUtils.sService.getUrl();
                    if(mCurrentPlaying != null){
                        int index = mCurrentPlaying.lastIndexOf('/');
                        if(index > 0){
                            mCurrentPlaying = mCurrentPlaying.substring(0, index);
                        }
                    }
                } catch (RemoteException e) {
                    e.printStackTrace();
                    mCurrentPlaying = null;
                }
            }

            getListView().invalidateViews();
            MusicUtils.updateNowPlaying(DirectoryBrowserActivity.this);
        }
    };

    private BroadcastReceiver mScanListener = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            MusicUtils.setSpinnerState(DirectoryBrowserActivity.this);
            mReScanHandler.removeMessages(0);
            mReScanHandler.sendEmptyMessage(0);
        }
    };

    private Handler mReScanHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            List<FolderItem> items = getFolderItemList();
            mAdapter.changeDatasource(items);
            mAdapter.notifyDataSetChanged();
            restorPrePosition();
        }
    };

    @Override
    public void onPause() {
        unregisterReceiver(mTrackListListener);
        mReScanHandler.removeCallbacksAndMessages(null);
        super.onPause();
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfoIn) {
        menu.add(0, PLAY_SELECTION, 0, R.string.play_selection);
        SubMenu sub = menu.addSubMenu(0, ADD_TO_PLAYLIST, 0, R.string.add_to_playlist);
        MusicUtils.makePlaylistMenu(this, sub);
        menu.add(0, DELETE_ITEM, 0, R.string.delete_item);

        AdapterContextMenuInfo mi = (AdapterContextMenuInfo) menuInfoIn;
        int position = mi.position;
        mCurrentSelectItem = mAdapter.getItem(position);
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case PLAY_SELECTION: {
                // play the selected folder
                long[] list = getTrackIdsByPath(mCurrentSelectItem.path);
                MusicUtils.playAll(this, list, 0);
                return true;
            }

            case QUEUE: {
                long[] list = getTrackIdsByPath(mCurrentSelectItem.path);
                MusicUtils.addToCurrentPlaylist(this, list);
                return true;
            }

            case NEW_PLAYLIST: {
                Intent intent = new Intent();
                intent.setClass(this, CreatePlaylist.class);
                startActivityForResult(intent, NEW_PLAYLIST);
                return true;
            }

            case PLAYLIST_SELECTED: {
                long[] list = getTrackIdsByPath(mCurrentSelectItem.path);
                long playlist = item.getIntent().getLongExtra("playlist", 0);
                MusicUtils.addToPlaylist(this, list, playlist);
                return true;
            }
            case DELETE_ITEM: {
                long[] list = getTrackIdsByPath(mCurrentSelectItem.path);
                String f;
                if (EnvironmentCompat.isExternalStorageRemovable()) {
                    f = getString(R.string.delete_folder_desc);
                } else {
                    f = getString(R.string.delete_folder_desc_nosdcard);
                }
                String desc = String.format(f, mCurrentSelectItem.name);
                Bundle b = new Bundle();
                b.putString("description", desc);
                b.putLongArray("items", list);
                Intent intent = new Intent();
                intent.setClass(this, DeleteItems.class);
                intent.putExtras(b);
                startActivityForResult(intent, DELETE_ITEM);
                return true;
            }
        }
        return super.onContextItemSelected(item);
    }

    private long[] getTrackIdsByPath(String path) {
        StringBuilder where = new StringBuilder();
        where.append(MediaStore.Audio.Media.TITLE + " != ''");
        where.append(" AND " + MediaStore.Audio.Media.IS_MUSIC + "=1");
        where.append(" AND " + MediaStore.Audio.Media.DATA + " LIKE '" + path + "/%'");
        where.append(" AND " + MediaStore.Audio.Media.DATA + " NOT LIKE '" + path + "/%/%'");
        Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        String[] projection = {
                MediaStore.Audio.Media._ID,
        };
        ContentResolver resolver = getContentResolver();
        Cursor cursor = resolver.query(
                uri, projection, where.toString(), null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
        long[] ids = MusicUtils.getSongListForCursor(cursor);
        if (cursor != null) {
            cursor.close();
        }
        return ids;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        switch (requestCode) {
            case DELETE_ITEM:
                // Let the DeleteObserver handle this event.
                // mReScanHandler.sendEmptyMessage(0);
                break;

            case SCAN_DONE:
                if (resultCode == RESULT_CANCELED) {
                    finish();
                } else {
                    mReScanHandler.removeMessages(0);
                    mReScanHandler.sendEmptyMessage(0);
                }
                break;

            case NEW_PLAYLIST:
                if (resultCode == RESULT_OK) {
                    Uri uri = intent.getData();
                    if (uri != null) {
                        long[] list = getTrackIdsByPath(mCurrentSelectItem.path);
                        MusicUtils.addToPlaylist(this, list, Long.parseLong(uri.getLastPathSegment()));
                    }
                }
                break;
        }
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setDataAndType(Uri.EMPTY, TypeDefs.TRACK);
        intent.putExtra("folderpath", mAdapter.getItem(position).path);
        intent.putExtra("foldername", mAdapter.getItem(position).name);
        startActivity(intent);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        menu.add(0, SHUFFLE_ALL, 0, R.string.shuffle_all).setIcon(R.drawable.ic_menu_shuffle);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Cursor cursor;
        switch (item.getItemId()) {
            case SHUFFLE_ALL:
                cursor = MusicUtils.query(this, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                        new String[] {
                            MediaStore.Audio.Media._ID
                        },
                        MediaStore.Audio.Media.IS_MUSIC + "=1", null,
                        MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
                if (cursor != null) {
                    MusicUtils.shuffleAll(this, cursor);
                    cursor.close();
                }
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    static class FolderListAdapter extends ArrayAdapter<FolderItem> {
        static class ViewHolder {
            TextView line1;
            TextView line2;
            ImageView play_indicator;
            ImageView icon;
            ImageView pop_menu;
        }

        private static final int LAYOUT_ID = R.layout.track_list_item;

        private Drawable mNowPlayingOverlay;
        private Drawable mFolderIcon;
        private LayoutInflater mInflater;

        List<FolderItem> mObjects;

        public FolderListAdapter(Context context, List<FolderItem> objects) {
            super(context, 0, objects);
            mObjects = objects;
            Resources r = context.getResources();
            mNowPlayingOverlay = r.getDrawable(R.drawable.indicator_ic_mp_playing_list);
            mFolderIcon = r.getDrawable(R.drawable.ic_mp_folder_list);
            mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public FolderItem getItem(int position) {
            return mObjects.get(position);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public int getCount() {
            if (mObjects == null) {
                return 0;
            }
            return mObjects.size();
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View returnView;
            ViewHolder vh;
            if (convertView == null) {
                returnView = mInflater.inflate(LAYOUT_ID, parent, false);
                vh = new ViewHolder();
                vh.line1 = (TextView) returnView.findViewById(R.id.line1);
                vh.line2 = (TextView) returnView.findViewById(R.id.line2);
                vh.play_indicator = (ImageView) returnView.findViewById(R.id.play_indicator);
                vh.pop_menu = (ImageView) returnView.findViewById(R.id.pop_menu);
                vh.pop_menu.setVisibility(View.VISIBLE);
                vh.pop_menu.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        v.showContextMenu();
                    }
                });
                vh.icon = (ImageView) returnView.findViewById(R.id.icon);
                vh.icon.setImageDrawable(mFolderIcon);
                returnView.setTag(vh);
            } else {
                returnView = convertView;
                vh = (ViewHolder) returnView.getTag();
            }

            FolderItem item = mObjects.get(position);
            vh.line1.setText(item.displayName);
            vh.line2.setText(item.path);

            if (mCurrentPlaying != null && mCurrentPlaying.equals(item.path)) {
                vh.play_indicator.setImageDrawable(mNowPlayingOverlay);
            } else {
                vh.play_indicator.setImageDrawable(null);
            }

            return returnView;
        }

        public void changeDatasource(List<FolderItem> items) {
                mObjects = items;
        }

        private Filter mFilter = null;
        /**
         * {@inheritDoc}
         */
        @Override
        public Filter getFilter() {
            if (mFilter == null) {
                mFilter = new MyFilter();
            }
            return mFilter;
        }

        private class MyFilter extends Filter {
            List<FolderItem> mOriginalValues;

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults results = new FilterResults();

                if (mOriginalValues == null) {
                    mOriginalValues = new ArrayList<FolderItem>(mObjects);
                }

                if (constraint == null || constraint.length() == 0) {
                    ArrayList<FolderItem> list = new ArrayList<FolderItem>(mOriginalValues);
                    results.values = list;
                    results.count = list.size();
                } else {
                    String prefixString = constraint.toString().toLowerCase();

                    final List<FolderItem> values = mOriginalValues;
                    final int count = values.size();

                    final List<FolderItem> newValues = new ArrayList<FolderItem>(count);

                    for (int i = 0; i < count; i++) {
                        final FolderItem value = values.get(i);
                        final String valueText = value.toString().toLowerCase();

                        // First match against the whole, non-splitted value
                        if (valueText.contains((prefixString))) {
                            newValues.add(value);
                        }
                    }

                    results.values = newValues;
                    results.count = newValues.size();
                }

                return results;
            }

            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                // no inspection unchecked
                mObjects = (List<FolderItem>) results.values;
                if (results.count > 0) {
                    notifyDataSetChanged();
                } else {
                    notifyDataSetInvalidated();
                }
            }

        }
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        MusicUtils.updateNowPlaying(this);
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        finish();
    }

    List<FolderItem> getFolderItemList() {
        List<FolderItem> folderItems = new ArrayList<FolderItem>();

        /* // SQL QUERY
        SELECT
          SUBSTR( _data, 1, LENGTH( _data ) - LENGTH( _display_name ) - 1 ) AS _PATH_,
          COUNT( * ) AS _SIZE_
        FROM audio
        WHERE
          (title != '' AND is_music = 1)
        GROUP BY
          (_PATH_);
        */
        Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        String[] projection = {
                // MediaStore.Audio.Media.DATA
                // MediaStore.Audio.Media.DISPLAY_NAME
                "SUBSTR(_data,1,LENGTH(_data)-LENGTH(_display_name)-1) AS _PATH_",
                "COUNT(*) AS _SIZE_"
        };

        StringBuffer where = new StringBuffer();
        where.append(MediaStore.Audio.Media.TITLE + " != '' AND ");
        where.append(MediaStore.Audio.Media.IS_MUSIC + "=1 ");
        // a hack method for use the 'GROUP BY' clause by ContentResolver
        // the ')' and '(' will completed by ContentResolver
        where.append(") GROUP BY (_PATH_");


        ContentResolver resolver = getContentResolver();
        Cursor cursor = resolver.query(uri, projection, where.toString(), null, null);
        if (cursor == null) {
            MusicUtils.displayDatabaseError(this);
            closeContextMenu();
            mReScanHandler.sendEmptyMessageDelayed(0, 1000);
            return folderItems;
        }

        while (cursor.moveToNext()) {
            String data = cursor.getString(0);
            int count = cursor.getInt(1);
            FolderItem item = new FolderItem();
            item.setData(data, count);
            folderItems.add(item);
        }
        cursor.close();

        MusicUtils.hideDatabaseError(this);

        return folderItems;
    }

    private DeleteObserver deleteObserver;

    private class DeleteObserver extends ContentObserver {
        public DeleteObserver() {
            super(new Handler());
        }

        @Override
        public void onChange(boolean selfChange) {
            // only update when no MediaScanService is working
            boolean isScanning = MusicUtils.isMediaScannerScanning(DirectoryBrowserActivity.this);
            if (!selfChange && !isScanning) {
                mReScanHandler.removeMessages(0);
                mReScanHandler.sendEmptyMessage(0);
            }
        }
    };

    // restore previous position
    private static int mLastListPosCourse = -1;
    private static int mLastListPosFine = -1;
    void restorPrePosition() {
        if (mLastListPosCourse >= 0) {
            getListView().setSelectionFromTop(mLastListPosCourse, mLastListPosFine);
            mLastListPosCourse = -1;
        }
    }

    class FolderItem {
        public String name;
        public String displayName;
        public String path;

        public void setData(String data, int count) {
            if (data != null) {
                path = data;
                int lastSep = data.lastIndexOf('/');
                if (lastSep != -1) {
                    name = data.substring(lastSep + 1);
                    displayName = getString(R.string.folder_songs_unit, name, count);
                }
            } else {
                path = null;
                name = null;
                displayName = null;
            }
        }

        @Override
        public String toString() {
            return path;
        }
    }
}
